package com.yzf.enterprise.framework.aspectj.aspect;

import com.yzf.enterprise.common.utils.JacksonUtil;
import com.yzf.enterprise.common.utils.ServletUtils;
import com.yzf.enterprise.common.utils.ip.IpUtils;
import com.yzf.enterprise.framework.aspectj.bo.LogBO;
import com.yzf.enterprise.framework.aspectj.lang.annotation.Log;
import com.yzf.enterprise.framework.aspectj.service.LogService;
import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.annotation.*;
import org.aspectj.lang.reflect.MethodSignature;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;

import java.lang.reflect.Method;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;

/**
 * <p>
 *  系统日志切面
 * </p>
 *
 * @author wangzhen
 * @since 2020-03-26
 */
@Aspect  // 使用@Aspect注解声明一个切面
@Component
public class LogAspect {
    private static final Logger log = LoggerFactory.getLogger(LogAspect.class);

    @Autowired
    private LogService sysLogService;

    /**
     * 这里我们使用注解的形式
     * 当然，我们也可以通过切点表达式直接指定需要拦截的package,需要拦截的class 以及 method
     * 切点表达式:   execution(...)
     */
    @Pointcut("@annotation(com.yzf.enterprise.framework.aspectj.lang.annotation.Log)")
    public void logPointCut() {}

    /**
     * 处理完请求后执行
     *
     * @param joinPoint 切点
     */
    @AfterReturning(pointcut = "logPointCut()", returning = "jsonResult")
    public void doAfterReturning(JoinPoint joinPoint, Object jsonResult) throws Throwable{
        saveLog(joinPoint,null,jsonResult);
    }

    /**
     * 拦截异常操作
     *
     * @param joinPoint 切点
     * @param e         异常
     */
    @AfterThrowing(value = "logPointCut()", throwing = "e")
    public void doAfterThrowing(JoinPoint joinPoint, Exception e) {
        saveLog(joinPoint, e, null);
    }

    /**
     * 保存日志
     * @param joinPoint
     * @param e
     * @param jsonResult
     */
    private void saveLog(JoinPoint joinPoint,final Exception e ,Object jsonResult) {
        MethodSignature signature = (MethodSignature) joinPoint.getSignature();
        Method method = signature.getMethod();
        // 请求的地址
        String ip = IpUtils.getIpAddr(ServletUtils.getRequest());
        LogBO sysLogBO = new LogBO();
        sysLogBO.setIp(ip);
        sysLogBO.setResult(jsonResult);
        SimpleDateFormat dateFormat = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
        sysLogBO.setCreateDate(dateFormat.format(new Date()));
        Log sysLog = method.getAnnotation(Log.class);
        if(sysLog != null){
            //注解上的描述
            sysLogBO.setRemark(sysLog.title());
        }
        //请求的 类名、方法名
        String className = joinPoint.getTarget().getClass().getName();
        String methodName = signature.getName();
        sysLogBO.setClassName(className);
        sysLogBO.setMethodName(methodName);
        //请求的参数
        Object[] args = joinPoint.getArgs();
        try{
            List<String> list = new ArrayList<String>();
            for (Object o : args) {
                list.add(JacksonUtil.toJson(o));
            }
            sysLogBO.setParams(list.toString());
        }catch (Exception ex){
            // 记录本地异常日志
            log.error("异常信息:{}", ex.getMessage());
        }
        sysLogService.save(sysLogBO);
    }
}
